Skip to content

fix(cpp-httplib-server): generate top-level enum models - #24795

Open
stefanwitkowskiwmb wants to merge 4 commits into
OpenAPITools:masterfrom
stefanwitkowskiwmb:bugfix/httplib-server_top_level_enum_schema
Open

fix(cpp-httplib-server): generate top-level enum models#24795
stefanwitkowskiwmb wants to merge 4 commits into
OpenAPITools:masterfrom
stefanwitkowskiwmb:bugfix/httplib-server_top_level_enum_schema

Conversation

@stefanwitkowskiwmb

@stefanwitkowskiwmb stefanwitkowskiwmb commented Aug 27, 2026

Copy link
Copy Markdown

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    (For Windows users, please run the script in WSL)
    Commit all changed files.
    This is important, as CI jobs will verify all generator outputs of your HEAD commit as it would merge with master.
    These must match the expectations made by your contribution.
    You may regenerate an individual generator by passing the relevant config(s) as an argument to the script, for example ./bin/generate-samples.sh bin/configs/java*.
    IMPORTANT: Do NOT purge/delete any folders/files (e.g. tests) when regenerating the samples as manually written tests may be removed.
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

Fix for #23902

@ravinikam @stkrwork @etherealjoy @MartinDelille @muttleyxd @aminya


Summary by cubic

Fixes the cpp-httplib-server generator so top-level enum schemas are emitted as enum class types with JSON serialization helpers. Previously, standalone enum models were not generated.

  • Serializes string-backed enums using the original spec strings (e.g. "active", not ACTIVE).
  • Adds the enum header include to the model source template.
  • Expands the feature-test schema and samples with a TopLevelStatus string enum and strengthens enumModelTest to assert top-level enums survive post-processing.

Written for commit ffbc0fa. Summary will update on new commits.

Review in cubic

@stefanwitkowskiwmb
stefanwitkowskiwmb marked this pull request as ready for review August 27, 2026 14:58

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 6 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache:40">
P2: The generated from_json in model-header.mustache compares `j == "active"`, but the committed sample TopLevelStatus.h (the expected generator output) uses `const std::string serializedValue = j.get<std::string>(); if (serializedValue == "active")`. The two implementations behave differently for non-string JSON and the sample will not match what the generator emits, so samples and generated code are out of sync. Align the template's from_json with the sample (or regenerate the sample to match the template).</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

inline void from_json(const nlohmann::json& j, {{vendorExtensions.modelClassName}}& value)
{
{{#allowableValues}}{{#enumVars}}
if (j == {{#isString}}"{{value}}"{{/isString}}{{^isString}}{{value}}{{/isString}})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The generated from_json in model-header.mustache compares j == "active", but the committed sample TopLevelStatus.h (the expected generator output) uses const std::string serializedValue = j.get<std::string>(); if (serializedValue == "active"). The two implementations behave differently for non-string JSON and the sample will not match what the generator emits, so samples and generated code are out of sync. Align the template's from_json with the sample (or regenerate the sample to match the template).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache, line 40:

<comment>The generated from_json in model-header.mustache compares `j == "active"`, but the committed sample TopLevelStatus.h (the expected generator output) uses `const std::string serializedValue = j.get<std::string>(); if (serializedValue == "active")`. The two implementations behave differently for non-string JSON and the sample will not match what the generator emits, so samples and generated code are out of sync. Align the template's from_json with the sample (or regenerate the sample to match the template).</comment>

<file context>
@@ -16,6 +17,37 @@
+inline void from_json(const nlohmann::json& j, {{vendorExtensions.modelClassName}}& value)
+{
+    {{#allowableValues}}{{#enumVars}}
+    if (j == {{#isString}}"{{value}}"{{/isString}}{{^isString}}{{value}}{{/isString}})
+    {
+        value = {{vendorExtensions.modelClassName}}::{{name}};
</file context>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 46 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.h">

<violation number="1" location="samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.h:10">
P3: The template now emits an unconditional `#include <string>` before the filteredImports block, so any model whose properties already pull in `<string>` (via filteredImports) gets a duplicate `#include <string>`. Verified: ErrorResponse.h and all other model headers with a std::string member (Address.h, Animal.h, CreatedResponse.h, etc.) now contain `#include <string>` twice, while enum-only headers like TopLevelStatus.h got the include exactly once. Emit `<string>` only when filteredImports does not already contain it (or add it to filteredImports in the codegen) so generated headers stay duplicate-free.</violation>
</file>

<file name="samples/server/petstore/cpp-httplib-server/petstore/models/Tag.h">

<violation number="1" location="samples/server/petstore/cpp-httplib-server/petstore/models/Tag.h:11">
P3: Every regenerated model header now contains a duplicated `#include <string>`: the template emits it unconditionally while `filteredImports` (from `postProcessAllModels`) emits it again for each model with a string member. It compiles because of the standard header guard, but it clutters every generated header. `model-header.mustache` should not hardcode `#include <string>`; let `filteredImports` provide it (as the master template did), or dedupe `<string>` in the import filter.</violation>
</file>

<file name="samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h">

<violation number="1" location="samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h:11">
P3: Generated model headers now emit a duplicate `#include <string>` for every model with a string member. The template hardcodes `#include <string>` while `filteredImports` (CppHttplibServerCodegen.java) already emits it for string-typed vars, so the two overlap in the output. Harmless at compile time, but it regresses generated-code cleanliness across all string-membered models. Drop the hardcoded `#include <string>` from model-header.mustache; the enum and string-member headers don't need it from the template since filteredImports supplies it (enum serialization uses string literals only).</violation>
</file>

<file name="samples/server/petstore/cpp-httplib-server/feature-test/models/Address.h">

<violation number="1" location="samples/server/petstore/cpp-httplib-server/feature-test/models/Address.h:11">
P3: Every generated model header in this PR now emits `#include <string>` twice: once from the template's new hardcoded include and once from the model's filtered imports. The template at model-header.mustache line 8 unconditionally writes `#include <string>` before `{{#vendorExtensions.filteredImports}}`, which itself also emits `<string>` for any model with a std::string field, so the two sources collide. De-duplicate (e.g. drop `<string>` from the template's hardcoded block when it is already in the model's imports) so generated output contains a single include.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread samples/server/petstore/cpp-httplib-server/feature-test/README.md Outdated
// System headers
#include <nlohmann/json.hpp>
#include <string>
#include <string>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Generated model headers now emit a duplicate #include <string> for every model with a string member. The template hardcodes #include <string> while filteredImports (CppHttplibServerCodegen.java) already emits it for string-typed vars, so the two overlap in the output. Harmless at compile time, but it regresses generated-code cleanliness across all string-membered models. Drop the hardcoded #include <string> from model-header.mustache; the enum and string-member headers don't need it from the template since filteredImports supplies it (enum serialization uses string literals only).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/cpp-httplib-server/feature-test/models/TestBasicSecurity200Response.h, line 11:

<comment>Generated model headers now emit a duplicate `#include <string>` for every model with a string member. The template hardcodes `#include <string>` while `filteredImports` (CppHttplibServerCodegen.java) already emits it for string-typed vars, so the two overlap in the output. Harmless at compile time, but it regresses generated-code cleanliness across all string-membered models. Drop the hardcoded `#include <string>` from model-header.mustache; the enum and string-member headers don't need it from the template since filteredImports supplies it (enum serialization uses string literals only).</comment>

<file context>
@@ -8,6 +8,7 @@
 // System headers
 #include <nlohmann/json.hpp>
 #include <string>
+#include <string>
 
 
</file context>

Comment thread samples/server/petstore/cpp-httplib-server/feature-test/models/EnumTypes.h Outdated
#pragma once
// System headers
#include <nlohmann/json.hpp>
#include <string>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The template now emits an unconditional #include <string> before the filteredImports block, so any model whose properties already pull in <string> (via filteredImports) gets a duplicate #include <string>. Verified: ErrorResponse.h and all other model headers with a std::string member (Address.h, Animal.h, CreatedResponse.h, etc.) now contain #include <string> twice, while enum-only headers like TopLevelStatus.h got the include exactly once. Emit <string> only when filteredImports does not already contain it (or add it to filteredImports in the codegen) so generated headers stay duplicate-free.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At samples/server/petstore/cpp-httplib-server/feature-test/models/ErrorResponse.h, line 10:

<comment>The template now emits an unconditional `#include <string>` before the filteredImports block, so any model whose properties already pull in `<string>` (via filteredImports) gets a duplicate `#include <string>`. Verified: ErrorResponse.h and all other model headers with a std::string member (Address.h, Animal.h, CreatedResponse.h, etc.) now contain `#include <string>` twice, while enum-only headers like TopLevelStatus.h got the include exactly once. Emit `<string>` only when filteredImports does not already contain it (or add it to filteredImports in the codegen) so generated headers stay duplicate-free.</comment>

<file context>
@@ -7,6 +7,7 @@
 #pragma once
 // System headers
 #include <nlohmann/json.hpp>
+#include <string>
 #include <cstdint>
 #include <string>
</file context>

Comment thread samples/server/petstore/cpp-httplib-server/feature-test/models/NotFoundResponse.h Outdated
Comment thread samples/server/petstore/cpp-httplib-server/feature-test/models/ArrayTypes.h Outdated
Comment thread samples/server/petstore/cpp-httplib-server/feature-test/models/Dog.h Outdated
Comment thread samples/server/petstore/cpp-httplib-server/petstore/models/User.h Outdated
Comment thread samples/server/petstore/cpp-httplib-server/feature-test/models/CreatedResponse.h Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 46 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache:31">
P1: When a top-level enum omits `type: string` but contains string values, `isStringEnum` can be false and the generator emits `j = available` instead of `j = "available"`. Determine stringness from the enum values as a fallback, or preserve the per-enum string flag for untyped enums.</violation>
</file>

<file name="modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenModelTest.java">

<violation number="1" location="modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenModelTest.java:284">
P3: The new assertion only verifies the internal `isStringEnum` vendor flag on the `fromModel` result, not the generated serialization output, and the test schema is always string-backed. Because the template switch now keys quoting off this single model-level flag, the `{{^vendorExtensions.isStringEnum}}` branch for integer-backed top-level enums has no coverage, so a regression in the rendered `to_json`/`from_json` output would go undetected. Render/check the generated enum header, or add a case for an integer-backed top-level enum.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

switch (value)
{
{{#allowableValues}}{{#enumVars}}
case {{vendorExtensions.modelClassName}}::{{name}}: j = {{#vendorExtensions.isStringEnum}}"{{{value}}}"{{/vendorExtensions.isStringEnum}}{{^vendorExtensions.isStringEnum}}{{value}}{{/vendorExtensions.isStringEnum}}; break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: When a top-level enum omits type: string but contains string values, isStringEnum can be false and the generator emits j = available instead of j = "available". Determine stringness from the enum values as a fallback, or preserve the per-enum string flag for untyped enums.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/cpp-httplib-server/model-header.mustache, line 31:

<comment>When a top-level enum omits `type: string` but contains string values, `isStringEnum` can be false and the generator emits `j = available` instead of `j = "available"`. Determine stringness from the enum values as a fallback, or preserve the per-enum string flag for untyped enums.</comment>

<file context>
@@ -29,15 +28,15 @@ inline void to_json(nlohmann::json& j, const {{vendorExtensions.modelClassName}}
     {
         {{#allowableValues}}{{#enumVars}}
-        case {{vendorExtensions.modelClassName}}::{{name}}: j = {{#isString}}"{{{value}}}"{{/isString}}{{^isString}}{{value}}{{/isString}}; break;
+        case {{vendorExtensions.modelClassName}}::{{name}}: j = {{#vendorExtensions.isStringEnum}}"{{{value}}}"{{/vendorExtensions.isStringEnum}}{{^vendorExtensions.isStringEnum}}{{value}}{{/vendorExtensions.isStringEnum}}; break;
         {{/enumVars}}{{/allowableValues}}
     }
</file context>

Assert.assertNotNull(model);
Assert.assertEquals(model.name, "Status");
Assert.assertTrue(model.isEnum, "top-level enum schemas must remain enum models");
Assert.assertEquals(model.vendorExtensions.get("isStringEnum"), true,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The new assertion only verifies the internal isStringEnum vendor flag on the fromModel result, not the generated serialization output, and the test schema is always string-backed. Because the template switch now keys quoting off this single model-level flag, the {{^vendorExtensions.isStringEnum}} branch for integer-backed top-level enums has no coverage, so a regression in the rendered to_json/from_json output would go undetected. Render/check the generated enum header, or add a case for an integer-backed top-level enum.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/test/java/org/openapitools/codegen/cpphttplibserver/CppHttplibServerCodegenModelTest.java, line 284:

<comment>The new assertion only verifies the internal `isStringEnum` vendor flag on the `fromModel` result, not the generated serialization output, and the test schema is always string-backed. Because the template switch now keys quoting off this single model-level flag, the `{{^vendorExtensions.isStringEnum}}` branch for integer-backed top-level enums has no coverage, so a regression in the rendered `to_json`/`from_json` output would go undetected. Render/check the generated enum header, or add a case for an integer-backed top-level enum.</comment>

<file context>
@@ -281,6 +281,8 @@ public void enumModelTest() {
         Assert.assertNotNull(model);
         Assert.assertEquals(model.name, "Status");
         Assert.assertTrue(model.isEnum, "top-level enum schemas must remain enum models");
+        Assert.assertEquals(model.vendorExtensions.get("isStringEnum"), true,
+                "string-backed top-level enums must serialize their values as JSON strings");
         Assert.assertNotNull(model.allowableValues);
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant